package uk.ac.kcl.cerch.r4r;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.DOMException;
import org.xml.sax.SAXException;

/**
 * Servlet implementation class Cerif4Ref
 */
public class Cerif4Ref extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	@Override
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		// Initialise default values
		String hostname = request.getServerName();
		String stylesheetpath = "/xslt/cerif4ref.xsl";
		int port = request.getServerPort();
				
		// Override from given params
		String hn = request.getParameter("hostname");
		if (hn != null && !hn.trim().isEmpty())
			hostname = hn;
		String pt = request.getParameter("port");
		if (pt != null && !pt.trim().isEmpty())
			port = Integer.parseInt(pt);
		
		URL stylesheet = getServletContext().getResource(stylesheetpath);		
		String styleurl = request.getParameter("style");
		if (styleurl != null && !styleurl.trim().isEmpty())
			stylesheet = new URL(styleurl);
		// bail out if we don't have a proper style-sheet URL
		if (stylesheet == null) {
			response.sendError(
					HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
						"Bad stylesheet URL");
			return;
		}
				
		// Create list of source URLs
		List<String> urls = new ArrayList<String>();
		String[] pids = request.getParameterValues("pid");
		if (pids != null) {
			for (String pid: pids)
				if (!pid.trim().isEmpty())
					urls.add(getDCUrlFromPid(hostname, port, pid));
		}
		String[] sources = request.getParameterValues("source");
		if (sources != null) {
			for (String url: request.getParameterValues("source"))
				if (!url.trim().isEmpty())
					urls.add(url);
		}
		// bail out early if no sources
		if (urls.size() == 0) {
			response.sendError(
					HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
						"No sources found");			
			return;
		}
		
		// Create a clean map of XSLT parameters
		Map<String,String> params = new HashMap<String,String>();
		for (Object key: request.getParameterMap().keySet()) {
			if (((String)key).matches("^(hostname|port|style|pid|source|zip)$"))
				continue;
			params.put((String)key, request.getParameter((String)key));
		}				
		
		// Create the processor, which actually does the work
		Cerif4RefProcessor processor = new Cerif4RefProcessor(
				urls, stylesheet.toString(), params);		
		String accept = request.getHeader("Accept");
		String zip = request.getParameter("zip");		
		try {
			if ((zip != null && Boolean.parseBoolean(zip.trim())) 
					|| (accept != null && accept.contains("application/zip"))) {
				response.setContentType("application/zip");
				response.setHeader("Content-Disposition", "attachment; filename=cerif4ref.zip");
				processor.writeZip(response.getOutputStream());
			} else {
				response.setContentType("text/xml");
				processor.writeXML(response.getOutputStream());
			}			
		} catch (FileNotFoundException e) {
			response.sendError(
					HttpServletResponse.SC_NOT_FOUND, e.getMessage());
		} catch (DOMException e) {
			response.sendError(
					HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
		} catch (SAXException e) {
			response.sendError(
					HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
	    } catch (TransformerException e) {		
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} 											
	}

	/**
	 * Get the RESTful path to the DC datastream given a Fedora
	 * pid.
	 * 
	 * @param hostname The hostname of the target Fedora Repository
	 * @param port The port of the target Fedora Repository
	 * @param pid The persistance ID of the resource.
	 * @return Fully-qualified path to the resource.
	 */
	private String getDCUrlFromPid(String hostname, int port, String pid) {
		return String.format(
				"http://%s:%d/fedora/objects/%s/datastreams/DC/content",
				hostname, port, pid);
	}
}
